home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
usenet
/
sources
/
volume89
/
unix
/
rcs.07
< prev
next >
Wrap
Internet Message Format
|
1989-11-19
|
86KB
Path: xanth!ames!apple!sun-barr!newstop!sun!swap!page
From: page%swap@Sun.COM (Bob Page)
Newsgroups: comp.sources.amiga
Subject: v89i222: rcs - revision control system, Part07/14
Message-ID: <128098@sun.Eng.Sun.COM>
Date: 19 Nov 89 09:25:07 GMT
Sender: news@sun.Eng.Sun.COM
Lines: 2809
Approved: page@sun.com
Submitted-by: rsbx@cbmvax.commodore.com (Raymond S. Brand)
Posting-number: Volume 89, Issue 222
Archive-name: unix/rcs.07
# This is a shell archive.
# Remove anything above and including the cut line.
# Then run the rest of the file through 'sh'.
# Unpacked files will be owned by you and have default permissions.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: SHell ARchive
# Run the following text through 'sh' to create:
# rcs/rcs.rcsfiles/partime.c,v
# rcs/rcs.rcsfiles/rcs.c,v
# This is archive 7 of a 14-part kit.
# This archive created: Sun Nov 19 01:12:08 1989
if `test ! -d rcs`
then
mkdir rcs
echo "mkdir rcs"
fi
if `test ! -d rcs/rcs.rcsfiles`
then
mkdir rcs/rcs.rcsfiles
echo "mkdir rcs/rcs.rcsfiles"
fi
echo "extracting rcs/rcs.rcsfiles/partime.c,v"
sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/partime.c,v
Xhead 1.4;
Xbranch 1.4.2;
Xaccess ;
Xsymbols amiga_rcs:1.4.2 cbmvax_source:1.4.1 uunet_june89_dist:1.4;
Xlocks ; strict;
Xcomment @ * @;
X
X
X1.4
Xdate 89.05.01.14.48.46; author narten; state Exp;
Xbranches 1.4.1.1 1.4.2.1;
Xnext ;
X
X1.4.1.1
Xdate 89.08.11.01.41.57; author rsbx; state Exp;
Xbranches ;
Xnext ;
X
X1.4.2.1
Xdate 89.10.13.19.17.41; author rsbx; state Exp;
Xbranches ;
Xnext 1.4.2.2;
X
X1.4.2.2
Xdate 89.10.15.15.43.31; author rsbx; state Exp;
Xbranches ;
Xnext 1.4.2.3;
X
X1.4.2.3
Xdate 89.10.29.14.47.46; author rsbx; state Exp;
Xbranches ;
Xnext ;
X
X
Xdesc
X@Parse date/time string into a TM structure.
X@
X
X
X
X1.4
Xlog
X@checked in with -k by rsbx at 89.08.10.16.06.05.
X@
Xtext
X@/*
X * PARTIME parse date/time string into a TM structure
X *
X * Usage:
X * #include "time.h" -- expanded tm structure
X * char *str; struct tm *tp;
X * partime(str,tp);
X * Returns:
X * 0 if parsing failed
X * else time values in specified TM structure (unspecified values
X * set to TMNULL)
X * Notes:
X * This code is quasi-public; it may be used freely in like software.
X * It is not to be sold, nor used in licensed software without
X * permission of the author.
X * For everyone's benefit, please report bugs and improvements!
X * Copyright 1980 by Ken Harrenstien, SRI International.
X * (ARPANET: KLH @@ SRI)
X */
X
X/* Hacknotes:
X * If parsing changed so that no backup needed, could perhaps modify
X * to use a FILE input stream. Need terminator, though.
X * Perhaps should return 0 on success, else a non-zero error val?
X * Flush AMPM from TM structure and handle locally within PARTIME,
X * like midnight/noon?
X */
X
X#ifndef lint
Xstatic char rcsid[]=
X"$Header: /usr/src/local/bin/rcs/src/RCS/partime.c,v 1.4 89/05/01 14:48:46 narten Exp $";
X#endif
X
X/* $Log: partime.c,v $
X * Revision 1.4 89/05/01 14:48:46 narten
X * fixed #ifdef DEBUG construct
X *
X * Revision 1.3 88/11/08 12:02:15 narten
X * changes from eggert@@sm.unisys.com (Paul Eggert)
X *
X * Revision 1.3 88/08/28 14:53:40 eggert
X * Remove unportable "#endif XXX"s.
X *
X * Revision 1.2 87/03/27 14:21:53 jenkins
X * Port to suns
X *
X * Revision 1.1 84/01/23 14:50:07 kcs
X * Initial revision
X *
X * Revision 1.1 82/05/06 11:38:26 wft
X * Initial revision
X *
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include "time.h"
X
X#ifndef lint
Xstatic char timeid[] = TIMEID;
X#endif
X
Xstruct tmwent {
X char *went;
X long wval; /* must be big enough to hold pointer or integer */
X char wflgs;
X char wtype;
X};
X /* wflgs */
X#define TWSPEC 01 /* Word wants special processing */
X#define TWTIME 02 /* Word is a time value (absence implies date) */
X#define TWDST 04 /* Word is a DST-type timezone */
X#define TW1200 010 /* Word is NOON or MIDNIGHT (sigh) */
X
Xint pt12hack();
Xint ptnoise();
Xstruct tmwent tmwords [] = {
X {"january", 0, 0, TM_MON},
X {"february", 1, 0, TM_MON},
X {"march", 2, 0, TM_MON},
X {"april", 3, 0, TM_MON},
X {"may", 4, 0, TM_MON},
X {"june", 5, 0, TM_MON},
X {"july", 6, 0, TM_MON},
X {"august", 7, 0, TM_MON},
X {"september", 8, 0, TM_MON},
X {"october", 9, 0, TM_MON},
X {"november", 10, 0, TM_MON},
X {"december", 11, 0, TM_MON},
X
X {"sunday", 0, 0, TM_WDAY},
X {"monday", 1, 0, TM_WDAY},
X {"tuesday", 2, 0, TM_WDAY},
X {"wednesday", 3, 0, TM_WDAY},
X {"thursday", 4, 0, TM_WDAY},
X {"friday", 5, 0, TM_WDAY},
X {"saturday", 6, 0, TM_WDAY},
X
X {"gmt", 0*60, TWTIME, TM_ZON}, /* Greenwich */
X {"gst", 0*60, TWTIME, TM_ZON},
X {"gdt", 0*60, TWTIME+TWDST, TM_ZON}, /* ?? */
X
X {"ast", 4*60, TWTIME, TM_ZON}, /* Atlantic */
X {"est", 5*60, TWTIME, TM_ZON}, /* Eastern */
X {"cst", 6*60, TWTIME, TM_ZON}, /* Central */
X {"mst", 7*60, TWTIME, TM_ZON}, /* Mountain */
X {"pst", 8*60, TWTIME, TM_ZON}, /* Pacific */
X {"yst", 9*60, TWTIME, TM_ZON}, /* Yukon */
X {"hst", 10*60, TWTIME, TM_ZON}, /* Hawaii */
X {"bst", 11*60, TWTIME, TM_ZON}, /* Bering */
X
X {"adt", 4*60, TWTIME+TWDST, TM_ZON}, /* Atlantic */
X {"edt", 5*60, TWTIME+TWDST, TM_ZON}, /* Eastern */
X {"cdt", 6*60, TWTIME+TWDST, TM_ZON}, /* Central */
X {"mdt", 7*60, TWTIME+TWDST, TM_ZON}, /* Mountain */
X {"pdt", 8*60, TWTIME+TWDST, TM_ZON}, /* Pacific */
X {"ydt", 9*60, TWTIME+TWDST, TM_ZON}, /* Yukon */
X {"hdt", 10*60, TWTIME+TWDST, TM_ZON}, /* Hawaii */
X {"bdt", 11*60, TWTIME+TWDST, TM_ZON}, /* Bering */
X
X {"daylight", 1, TWTIME+TWDST, TM_ZON}, /* Local Daylight */
X {"standard", 1, TWTIME, TM_ZON}, /* Local Standard */
X {"std", 1, TWTIME, TM_ZON}, /* " " */
X
X {"am", 1, TWTIME, TM_AMPM},
X {"pm", 2, TWTIME, TM_AMPM},
X {"noon", 12,TWTIME+TW1200, 0}, /* Special frobs */
X {"midnight", 0, TWTIME+TW1200, 0},
X {"at", (long)ptnoise, TWSPEC, 0}, /* Noise word */
X
X {0, 0, 0, 0}, /* Zero entry to terminate searches */
X};
X
X#define TMWILD (-2) /* Value meaning item specified as wild-card */
X /* (May use someday...) */
X
Xstruct token {
X char *tcp; /* pointer to string */
X int tcnt; /* # chars */
X char tbrk; /* "break" char */
X char tbrkl; /* last break char */
X char tflg; /* 0 = alpha, 1 = numeric */
X union { /* Resulting value; */
X int tnum;/* either a #, or */
X struct tmwent *ttmw;/* ptr to a tmwent. */
X } tval;
X};
X
Xpartime(astr, atm)
Xchar *astr;
Xstruct tm *atm;
X{ register int *tp;
X register struct tmwent *twp;
X register int i;
X struct token btoken, atoken;
X char *cp, ch;
X int ord, midnoon;
X int (*aproc)();
X
X tp = (int *)atm;
X zaptime(tp); /* Initialize the TM structure */
X midnoon = TMNULL; /* and our own temp stuff */
X btoken.tcnt = btoken.tbrkl = 0;
X btoken.tcp = astr;
X
Xdomore:
X if(!ptitoken(btoken.tcp+btoken.tcnt,&btoken)) /* Get a token */
X { if(btoken.tval.tnum) return(0); /* Read error? */
X if(midnoon != TMNULL) /* EOF, wrap up */
X return(pt12hack(tp, midnoon));
X return(1); /* Win return! */
X }
X if(btoken.tflg == 0) /* Alpha? */
X { twp = btoken.tval.ttmw; /* Yes, get ptr to entry */
X if(twp->wflgs&TWSPEC) /* Special alpha crock */
X { aproc = (int (*) ()) (twp->wval);
X if(!(*aproc)(tp, twp, &btoken))
X return(0); /* ERR: special word err */
X goto domore;
X }
X if(twp->wflgs&TW1200)
X if(ptstash(&midnoon,(int)twp->wval))
X return(0); /* ERR: noon/midnite clash */
X else goto domore;
X if(ptstash(&tp[twp->wtype],(int)twp->wval))
X return(0); /* ERR: val already set */
X if(twp->wtype == TM_ZON) /* If was zone, hack DST */
X if(ptstash(&tp[TM_ISDST],(twp->wflgs&TWDST)))
X return(0); /* ERR: DST conflict */
X goto domore;
X }
X
X /* Token is number. Lots of hairy heuristics. */
X if(btoken.tcnt >= 7) /* More than 6 digits in string? */
X return(0); /* ERR: number too big */
X if(btoken.tcnt == 6) /* 6 digits = HHMMSS. Needs special crock */
X { /* since 6 digits are too big for integer! */
X i = (btoken.tcp[0]-'0')*10 /* Gobble 1st 2 digits */
X + btoken.tcp[1]-'0';
X btoken.tcnt = 2; /* re-read last 4 chars */
X goto coltime;
X }
X
X i = btoken.tval.tnum; /* Value now known to be valid; get it. */
X if( btoken.tcnt == 5 /* 5 digits = HMMSS */
X || btoken.tcnt == 3) /* 3 digits = HMM */
X { if(btoken.tcnt != 3)
X if(ptstash(&tp[TM_SEC], i%100))
X return(0); /* ERR: sec conflict */
X else i /= 100;
Xhhmm4: if(ptstash(&tp[TM_MIN], i%100))
X return(0); /* ERR: min conflict */
X i /= 100;
Xhh2: if(ptstash(&tp[TM_HOUR], i))
X return(0); /* ERR: hour conflict */
X goto domore;
X }
X
X if(btoken.tcnt == 4) /* 4 digits = YEAR or HHMM */
X { if(tp[TM_YEAR] != TMNULL) goto hhmm4; /* Already got yr? */
X if(tp[TM_HOUR] != TMNULL) goto year4; /* Already got hr? */
X if((i%100) > 59) goto year4; /* MM >= 60? */
X if(btoken.tbrk == ':') /* HHMM:SS ? */
X if( ptstash(&tp[TM_HOUR],i/100)
X || ptstash(&tp[TM_MIN], i%100))
X return(0); /* ERR: hr/min clash */
X else goto coltm2; /* Go handle SS */
X if(btoken.tbrk != ',' && btoken.tbrk != '/'
X && ptitoken(btoken.tcp+btoken.tcnt,&atoken) /* Peek */
X && atoken.tflg == 0 /* alpha */
X && (atoken.tval.ttmw->wflgs&TWTIME)) /* HHMM-ZON */
X goto hhmm4;
X if(btoken.tbrkl == '-' /* DD-Mon-YYYY */
X || btoken.tbrkl == ',' /* Mon DD, YYYY */
X || btoken.tbrkl == '/' /* MM/DD/YYYY */
X || btoken.tbrkl == '.' /* DD.MM.YYYY */
X || btoken.tbrk == '-' /* YYYY-MM-DD */
X ) goto year4;
X goto hhmm4; /* Give up, assume HHMM. */
X }
X
X /* From this point on, assume tcnt == 1 or 2 */
X /* 2 digits = YY, MM, DD, or HH (MM and SS caught at coltime) */
X if(btoken.tbrk == ':') /* HH:MM[:SS] */
X goto coltime; /* must be part of time. */
X if(i > 31) goto yy2; /* If >= 32, only YY poss. */
X
X /* Check for numerical-format date */
X for (cp = "/-."; ch = *cp++;)
X { ord = (ch == '.' ? 0 : 1); /* n/m = D/M or M/D */
X if(btoken.tbrk == ch) /* "NN-" */
X { if(btoken.tbrkl != ch)
X { if(ptitoken(btoken.tcp+btoken.tcnt,&atoken)
X && atoken.tflg == 0
X && atoken.tval.ttmw->wtype == TM_MON)
X goto dd2;
X if(ord)goto mm2; else goto dd2; /* "NN-" */
X } /* "-NN-" */
X if(tp[TM_DAY] == TMNULL
X && tp[TM_YEAR] != TMNULL) /* If "YY-NN-" */
X goto mm2; /* then always MM */
X if(ord)goto dd2; else goto mm2;
X }
X if(btoken.tbrkl == ch /* "-NN" */
X && tp[ord ? TM_MON : TM_DAY] != TMNULL)
X if(tp[ord ? TM_DAY : TM_MON] == TMNULL) /* MM/DD */
X if(ord)goto dd2; else goto mm2;
X else goto yy2; /* "-YY" */
X }
X
X /* At this point only YY, DD, and HH are left.
X * YY is very unlikely since value is <= 32 and there was
X * no numerical format date. Make one last try at YY
X * before dropping through to DD vs HH code.
X */
X if(btoken.tcnt == 2 /* If 2 digits */
X && tp[TM_HOUR] != TMNULL /* and already have hour */
X && tp[TM_DAY] != TMNULL /* and day, but */
X && tp[TM_YEAR] == TMNULL) /* no year, then assume */
X goto yy2; /* that's what we have. */
X
X /* Now reduced to choice between HH and DD */
X if(tp[TM_HOUR] != TMNULL) goto dd2; /* Have hour? Assume day. */
X if(tp[TM_DAY] != TMNULL) goto hh2; /* Have day? Assume hour. */
X if(i > 24) goto dd2; /* Impossible HH means DD */
X if(!ptitoken(btoken.tcp+btoken.tcnt, &atoken)) /* Read ahead! */
X if(atoken.tval.tnum) return(0); /* ERR: bad token */
X else goto dd2; /* EOF, assume day. */
X if( atoken.tflg == 0 /* If next token is an alpha */
X && atoken.tval.ttmw->wflgs&TWTIME) /* time-spec, assume hour */
X goto hh2; /* e.g. "3 PM", "11-EDT" */
X
Xdd2: if(ptstash(&tp[TM_DAY],i)) /* Store day (1 based) */
X return(0);
X goto domore;
X
Xmm2: if(ptstash(&tp[TM_MON], i-1)) /* Store month (make zero based) */
X return(0);
X goto domore;
X
Xyy2: i += 1900;
Xyear4: if(ptstash(&tp[TM_YEAR],i)) /* Store year (full number) */
X return(0); /* ERR: year conflict */
X goto domore;
X
X /* Hack HH:MM[[:]SS] */
Xcoltime:
X if(ptstash(&tp[TM_HOUR],i)) return(0);
X if(!ptitoken(btoken.tcp+btoken.tcnt,&btoken))
X return(!btoken.tval.tnum);
X if(!btoken.tflg) return(0); /* ERR: HH:<alpha> */
X if(btoken.tcnt == 4) /* MMSS */
X if(ptstash(&tp[TM_MIN],btoken.tval.tnum/100)
X || ptstash(&tp[TM_SEC],btoken.tval.tnum%100))
X return(0);
X else goto domore;
X if(btoken.tcnt != 2
X || ptstash(&tp[TM_MIN],btoken.tval.tnum))
X return(0); /* ERR: MM bad */
X if(btoken.tbrk != ':') goto domore; /* Seconds follow? */
Xcoltm2: if(!ptitoken(btoken.tcp+btoken.tcnt,&btoken))
X return(!btoken.tval.tnum);
X if(!btoken.tflg || btoken.tcnt != 2 /* Verify SS */
X || ptstash(&tp[TM_SEC], btoken.tval.tnum))
X return(0); /* ERR: SS bad */
X goto domore;
X}
X
X/* Store date/time value, return 0 if successful.
X * Fails if entry already set to a different value.
X */
Xptstash(adr,val)
Xint *adr;
X{ register int *a;
X if( *(a=adr) != TMNULL)
X return(*a != val);
X *a = val;
X return(0);
X}
X
X/* This subroutine is invoked for NOON or MIDNIGHT when wrapping up
X * just prior to returning from partime.
X */
Xpt12hack(atp, aval)
Xint *atp, aval;
X{ register int *tp, i, h;
X tp = atp;
X if (((i=tp[TM_MIN]) && i != TMNULL) /* Ensure mins, secs */
X || ((i=tp[TM_SEC]) && i != TMNULL)) /* are 0 or unspec'd */
X return(0); /* ERR: MM:SS not 00:00 */
X i = aval; /* Get 0 or 12 (midnite or noon) */
X if ((h = tp[TM_HOUR]) == TMNULL /* If hour unspec'd, win */
X || h == 12) /* or if 12:00 (matches either) */
X tp[TM_HOUR] = i; /* Then set time */
X else if(!(i == 0 /* Nope, but if midnight and */
X &&(h == 0 || h == 24))) /* time matches, can pass. */
X return(0); /* ERR: HH conflicts */
X tp[TM_AMPM] = TMNULL; /* Always reset this value if won */
X return(1);
X}
X
X/* Null routine for no-op tokens */
X
Xptnoise() { return(1); }
X
X/* Get a token and identify it to some degree.
X * Returns 0 on failure; token.tval will be 0 for normal EOF, otherwise
X * hit error of some sort
X */
X
Xptitoken(astr, tkp)
Xregister struct token *tkp;
Xchar *astr;
X{
X register char *cp;
X register int i;
X
X tkp->tval.tnum = 0;
X if(pttoken(astr,tkp) == 0)
X#ifdef DEBUG
X {
X VOID printf("EOF\n");
X return(0);
X }
X#else
X return(0);
X#endif
X cp = tkp->tcp;
X
X#ifdef DEBUG
X i = cp[tkp->tcnt];
X cp[tkp->tcnt] = 0;
X VOID printf("Token: \"%s\" ",cp);
X cp[tkp->tcnt] = i;
X#endif
X
X if(tkp->tflg)
X for(i = tkp->tcnt; i > 0; i--)
X tkp->tval.tnum = (int)tkp->tval.tnum*10 + ((*cp++)-'0');
X else
X { i = ptmatchstr(cp, tkp->tcnt, tmwords);
X tkp->tval.tnum = i ? i : -1; /* Set -1 for error */
X
X#ifdef DEBUG
X if(!i) VOID printf("Not found!\n");
X#endif
X
X if(!i) return(0);
X }
X
X#ifdef DEBUG
X if(tkp->tflg)
X VOID printf("Val: %d.\n",tkp->tval.tnum);
X else VOID printf("Found: \"%s\", val: %d., type %d\n",
X tkp->tval.ttmw->went,tkp->tval.ttmw->wval,tkp->tval.ttmw->wtype);
X#endif
X
X return(1);
X}
X
X/* Read token from input string into token structure */
Xpttoken(astr,tkp)
Xregister struct token *tkp;
Xchar *astr;
X{
X register char *cp;
X register int c;
X
X tkp->tcp = cp = astr;
X tkp->tbrkl = tkp->tbrk; /* Set "last break" */
X tkp->tcnt = tkp->tbrk = tkp->tflg = 0;
X
X while(c = *cp++)
X { switch(c)
X { case ' ': case '\t': /* Flush all whitespace */
X while((c = *cp++) && isspace(c));
X cp--; /* Drop thru to handle brk */
X case '(': case ')': /* Perhaps any non-alphanum */
X case '-': case ',': /* shd qualify as break? */
X case '/': case ':': case '.': /* Break chars */
X if(tkp->tcnt == 0) /* If no token yet */
X { tkp->tcp = cp; /* ignore the brk */
X tkp->tbrkl = c;
X continue; /* and go on. */
X }
X tkp->tbrk = c;
X return(tkp->tcnt);
X }
X if(tkp->tcnt == 0) /* If first char of token, */
X tkp->tflg = isdigit(c); /* determine type */
X if(( isdigit(c) && tkp->tflg) /* If not first, make sure */
X ||(!isdigit(c) && !tkp->tflg)) /* char matches type */
X tkp->tcnt++; /* Win, add to token. */
X else {
X cp--; /* Wrong type, back up */
X tkp->tbrk = c;
X return(tkp->tcnt);
X }
X }
X return(tkp->tcnt); /* When hit EOF */
X}
X
X
Xptmatchstr(astr,cnt,astruc)
Xchar *astr;
Xint cnt;
Xstruct tmwent *astruc;
X{ register char *cp, *mp;
X register int c;
X struct tmwent *lastptr;
X struct integ { int word; }; /* For getting at array ptr */
X int i;
X
X lastptr = 0;
X for(;mp = (char *)((struct integ *)astruc)->word; astruc += 1)
X { cp = astr;
X for(i = cnt; i > 0; i--)
X { switch((c = *cp++) ^ *mp++) /* XOR the chars */
X { case 0: continue; /* Exact match */
X case 040: if(isalpha(c))
X continue;
X }
X break;
X }
X if(i==0)
X if(*mp == 0) return((unsigned int)astruc); /* Exact match */
X else if(lastptr) return(0); /* Ambiguous */
X else lastptr = astruc; /* 1st ambig */
X }
X return((unsigned int)lastptr);
X}
X
X
X
Xzaptime(tp)
Xregister int *tp;
X/* clears tm structure pointed to by tp */
X{ register int i;
X i = (sizeof (struct tm))/(sizeof (int));
X do *tp++ = TMNULL; /* Set entry to "unspecified" */
X while(--i); /* Faster than FOR */
X}
X@
X
X
X1.4.2.1
Xlog
X@Start of Amiga RCS port branch.
X@
Xtext
X@d31 1
Xa31 5
X<<<<<<< partime.c
X"$Header: /u/softeng/rsbx/rcs/amiga/RCS.cbmvax/partime.c,v 1.4.1.1 89/08/11 01:41:57 rsbx Exp Locker: rsbx $";
X=======
X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/partime.c,v 1.2 89/09/17 13:34:54 rick Exp $";
X>>>>>>> 1.2
Xa34 11
X<<<<<<< partime.c
X * Revision 1.4.1.1 89/08/11 01:41:57 rsbx
X * Start of cbmvax RCS source branch.
X=======
X * Revision 1.2 89/09/17 13:34:54 rick
X * Port to AmigaDos done by Rick Schaeffer (ricks@@iscuva.iscs.com)
X * All changes done with conditional compile (#ifdef AMIGA). This version
X * compiles correctly with Lattice C version 5.02 or later.
X>>>>>>> 1.2
X *
X<<<<<<< partime.c
Xa35 3
X * checked in with -k by rsbx at 89.08.10.16.06.05.
X *
X * Revision 1.4 89/05/01 14:48:46 narten
Xa43 8
X=======
X * Revision 1.3 89/09/16 09:42:36 rick
X * Modified AMIGA changes to work with Lattice C
X *
X * Revision 1.2 88/09/03 15:08:16 rick
X * Port to AmigaDos. All done with conditional compiles
X *
X>>>>>>> 1.2
Xa58 1
X#ifndef AMIGA
Xa61 1
X#endif
Xd76 1
Xa76 1
Xlong ptnoise();
Xd129 1
Xa129 1
X {"at", 1, 0, 0}, /* Noise word */
Xd152 1
Xa152 2
X{
X register int *tp;
Xa332 3
X#ifdef AMIGA
Xshort *adr;
X#else
Xd334 1
Xa334 7
X#endif
X{
X#ifdef AMIGA
X register short *a;
X#else
X register int *a;
X#endif
Xa344 3
X#ifdef AMIGA
Xshort *atp, aval;
X#else
Xd346 1
Xa346 7
X#endif
X{
X#ifdef AMIGA
X register short *tp, i, h;
X#else
X register int *tp, i, h;
X#endif
Xd364 1
Xa364 1
Xlong ptnoise() { return(1); }
Xa379 1
X<<<<<<< partime.c
Xa382 5
X=======
X#ifdef MYDEBUG
X VOID printf("EOF\n");
X#endif MYDEBUG
X>>>>>>> 1.2
Xd390 1
Xa390 1
X#ifdef MYDEBUG
Xa394 1
X<<<<<<< partime.c
Xa395 3
X=======
X#endif MYDEBUG
X>>>>>>> 1.2
Xd404 1
Xa404 1
X#ifdef MYDEBUG
Xa405 1
X<<<<<<< partime.c
Xa406 3
X=======
X#endif MYDEBUG
X>>>>>>> 1.2
Xd411 1
Xa411 1
X#ifdef MYDEBUG
Xa415 1
X<<<<<<< partime.c
Xa416 3
X=======
X#endif MYDEBUG
X>>>>>>> 1.2
Xa495 3
X#ifdef AMIGA
Xregister short *tp;
X#else
Xa496 1
X#endif
Xa498 3
X#ifdef AMIGA
X i = (sizeof (struct tm))/(sizeof (short));
X#else
Xa499 1
X#endif
X@
X
X
X1.4.2.2
Xlog
X@Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS
Xsources I have here (and are later than the ones Rick used).
X@
Xtext
X@d31 5
Xa35 1
X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/partime.c,v 1.4.2.1 89/10/13 19:17:41 rsbx Exp Locker: rsbx $";
Xd39 1
Xa39 3
X * Revision 1.4.2.1 89/10/13 19:17:41 rsbx
X * Start of Amiga RCS port branch.
X *
Xd42 6
Xd49 1
Xd62 8
Xd427 2
Xa428 1
X#ifdef MYDEBUG
Xd431 5
Xd448 1
Xd450 3
Xd463 1
Xd465 3
Xd477 1
Xd479 3
Xd520 1
X@
X
X
X1.4.2.3
Xlog
X@Changed $Header$ to $Id$.
X@
Xtext
X@d31 1
Xa31 1
X"$Id$";
Xa34 4
X * Revision 1.4.2.2 89/10/15 15:43:31 rsbx
X * Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS
X * sources I have here (and are later than the ones Rick used).
X *
X@
X
X
X1.4.1.1
Xlog
X@Start of cbmvax RCS source branch.
X@
Xtext
X@d31 1
Xa31 1
X"$Header: /u/softeng/rsbx/rcs/rcs.uunet/src/RCS/partime.c,v 1.4 89/05/01 14:48:46 narten Exp $";
Xa34 3
X * Revision 1.4 89/05/01 14:48:46 narten
X * checked in with -k by rsbx at 89.08.10.16.06.05.
X *
X@
SHAR_EOF
echo "extracting rcs/rcs.rcsfiles/rcs.c,v"
sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/rcs.c,v
Xhead 4.11;
Xbranch 4.11.2;
Xaccess ;
Xsymbols amiga_rcs:4.11.2 cbmvax_source:4.11.1 uunet_june89_dist:4.11;
Xlocks ; strict;
Xcomment @ * @;
X
X
X4.11
Xdate 89.05.01.15.12.06; author narten; state Exp;
Xbranches 4.11.1.1 4.11.2.1;
Xnext ;
X
X4.11.1.1
Xdate 89.08.11.01.42.01; author rsbx; state Exp;
Xbranches ;
Xnext ;
X
X4.11.2.1
Xdate 89.10.13.19.17.47; author rsbx; state Exp;
Xbranches ;
Xnext 4.11.2.2;
X
X4.11.2.2
Xdate 89.10.15.15.43.36; author rsbx; state Exp;
Xbranches ;
Xnext 4.11.2.3;
X
X4.11.2.3
Xdate 89.10.16.19.06.13; author rsbx; state Exp;
Xbranches ;
Xnext 4.11.2.4;
X
X4.11.2.4
Xdate 89.10.17.13.17.35; author rsbx; state Exp;
Xbranches ;
Xnext 4.11.2.5;
X
X4.11.2.5
Xdate 89.10.30.13.38.35; author rsbx; state Exp;
Xbranches ;
Xnext 4.11.2.6;
X
X4.11.2.6
Xdate 89.11.01.14.42.32; author rsbx; state Exp;
Xbranches ;
Xnext 4.11.2.7;
X
X4.11.2.7
Xdate 89.11.05.23.14.17; author rsbx; state Exp;
Xbranches ;
Xnext 4.11.2.8;
X
X4.11.2.8
Xdate 89.11.12.15.07.03; author rsbx; state Exp;
Xbranches ;
Xnext ;
X
X
Xdesc
X@RCS create/change operation.
X@
X
X
X
X4.11
Xlog
X@checked in with -k by rsbx at 89.08.10.16.06.26.
X@
Xtext
X@/*
X * RCS create/change operation
X */
X#ifndef lint
Xstatic char rcsid[]=
X"$Header: /usr/src/local/bin/rcs/src/RCS/rcs.c,v 4.11 89/05/01 15:12:06 narten Exp $ Purdue CS";
X#endif
X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by Walter Tichy.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X * Report all problems and direct all questions to:
X * rcs-bugs@@cs.purdue.edu
X *
X
X
X
X
X
X
X
X*/
X
X
X
X
X/* $Log: rcs.c,v $
X * Revision 4.11 89/05/01 15:12:06 narten
X * changed copyright header to reflect current distribution rules
X *
X * Revision 4.10 88/11/08 16:01:54 narten
X * didn't install previous patch correctly
X *
X * Revision 4.9 88/11/08 13:56:01 narten
X * removed include <sysexits.h> (not needed)
X * minor fix for -A option
X *
X * Revision 4.8 88/11/08 12:01:58 narten
X * changes from eggert@@sm.unisys.com (Paul Eggert)
X *
X * Revision 4.8 88/08/09 19:12:27 eggert
X * Don't access freed storage.
X * Use execv(), not system(); yield proper exit status; remove lint.
X *
X * Revision 4.7 87/12/18 11:37:17 narten
X * lint cleanups (Guy Harris)
X *
X * Revision 4.6 87/10/18 10:28:48 narten
X * Updating verison numbers. Changes relative to 1.1 are actually
X * relative to 4.3
X *
X * Revision 1.4 87/09/24 13:58:52 narten
X * Sources now pass through lint (if you ignore printf/sprintf/fprintf
X * warnings)
X *
X * Revision 1.3 87/03/27 14:21:55 jenkins
X * Port to suns
X *
X * Revision 1.2 85/12/17 13:59:09 albitz
X * Changed setstate to rcs_setstate because of conflict with random.o.
X *
X * Revision 1.1 84/01/23 14:50:09 kcs
X * Initial revision
X *
X * Revision 4.3 83/12/15 12:27:33 wft
X * rcs -u now breaks most recent lock if it can't find a lock by the caller.
X *
X * Revision 4.2 83/12/05 10:18:20 wft
X * Added conditional compilation for sending mail.
X * Alternatives: V4_2BSD, V6, USG, and other.
X *
X * Revision 4.1 83/05/10 16:43:02 wft
X * Simplified breaklock(); added calls to findlock() and getcaller().
X * Added option -b (default branch). Updated -s and -w for -b.
X * Removed calls to stat(); now done by pairfilenames().
X * Replaced most catchints() calls with restoreints().
X * Removed check for exit status of delivermail().
X * Directed all interactive output to stderr.
X *
X * Revision 3.9.1.1 83/12/02 22:08:51 wft
X * Added conditional compilation for 4.2 sendmail and 4.1 delivermail.
X *
X * Revision 3.9 83/02/15 15:38:39 wft
X * Added call to fastcopy() to copy remainder of RCS file.
X *
X * Revision 3.8 83/01/18 17:37:51 wft
X * Changed sendmail(): now uses delivermail, and asks whether to break the lock.
X *
X * Revision 3.7 83/01/15 18:04:25 wft
X * Removed putree(); replaced with puttree() in rcssyn.c.
X * Combined putdellog() and scanlogtext(); deleted putdellog().
X * Cleaned up diagnostics and error messages. Fixed problem with
X * mutilated files in case of deletions in 2 files in a single command.
X * Changed marking of selector from 'D' to DELETE.
X *
X * Revision 3.6 83/01/14 15:37:31 wft
X * Added ignoring of interrupts while new RCS file is renamed;
X * Avoids deletion of RCS files by interrupts.
X *
X * Revision 3.5 82/12/10 21:11:39 wft
X * Removed unused variables, fixed checking of return code from diff,
X * introduced variant COMPAT2 for skipping Suffix on -A files.
X *
X * Revision 3.4 82/12/04 13:18:20 wft
X * Replaced getdelta() with gettree(), changed breaklock to update
X * field lockedby, added some diagnostics.
X *
X * Revision 3.3 82/12/03 17:08:04 wft
X * Replaced getlogin() with getpwuid(), flcose() with ffclose(),
X * /usr/ucb/Mail with macro MAIL. Removed handling of Suffix (-x).
X * fixed -u for missing revno. Disambiguated structure members.
X *
X * Revision 3.2 82/10/18 21:05:07 wft
X * rcs -i now generates a file mode given by the umask minus write permission;
X * otherwise, rcs keeps the mode, but removes write permission.
X * I added a check for write error, fixed call to getlogin(), replaced
X * curdir() with getfullRCSname(), cleaned up handling -U/L, and changed
X * conflicting, long identifiers.
X *
X * Revision 3.1 82/10/13 16:11:07 wft
X * fixed type of variables receiving from getc() (char -> int).
X */
X
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "rcsbase.h"
X#ifndef lint
Xstatic char rcsbaseid[] = RCSBASE;
X#endif
X
Xextern FILE * fopen();
Xextern char * bindex();
Xextern int expandsym(); /* get numeric revision name */
Xextern struct hshentry * getnum();
Xextern struct lock * addlock(); /* add a lock */
Xextern char * getid();
Xextern char Klog[], Khead[], Kaccess[], Kbranch[], Ktext[];
X#ifdef COMPAT2
Xextern char Ksuffix[];
X#endif
Xextern char * getcaller(); /* get login of caller */
Xextern struct hshentry * findlock(); /* find and remove lock */
Xextern struct hshentry * genrevs();
Xextern char * checkid(); /* check an identifier */
Xextern char * getfullRCSname(); /* get full path name of RCS file */
Xextern char * mktempfile(); /* temporary file name generator */
Xextern free();
Xextern void catchints();
Xextern void ignoreints();
Xextern int nerror; /* counter for errors */
Xextern int quietflag; /* diagnoses suppressed if true */
Xextern char curlogmsg[]; /* current log message */
Xextern char * resultfile; /* filename for fcopy */
Xextern FILE *fcopy; /* result file during editing */
Xextern FILE * finptr; /* RCS input file */
Xextern FILE * frewrite; /* new RCS file */
Xextern int rewriteflag; /* indicates whether input should be*/
X /* echoed to frewrite */
X
Xchar * newRCSfilename, * diffilename, * cutfilename;
Xchar * RCSfilename, * workfilename;
Xextern struct stat RCSstat, workstat; /* file status of RCS and work file */
Xextern int haveRCSstat, haveworkstat;/* status indicators */
X
Xchar accessorlst[strtsize];
XFILE * fcut; /* temporary file to rebuild delta tree */
Xint oldumask; /* save umask */
X
Xint initflag, strictlock, strict_selected, textflag;
Xchar * textfile, * accessfile;
Xchar * caller, numrev[30]; /* caller's login; */
Xstruct access * newaccessor, * rmvaccessor, * rplaccessor;
Xstruct access *curaccess, *rmaccess;
Xstruct hshentry * gendeltas[hshsize];
X
Xstruct Lockrev {
X char * revno;
X struct Lockrev * nextrev;
X};
X
Xstruct Symrev {
X char * revno;
X char * ssymbol;
X int override;
X struct Symrev * nextsym;
X};
X
Xstruct Status {
X char * revno;
X char * status;
X struct Status * nextstatus;
X};
X
Xstruct delrevpair {
X char * strt;
X char * end;
X int code;
X};
X
Xstruct Lockrev * newlocklst, * rmvlocklst;
Xstruct Symrev * assoclst, * lastassoc;
Xstruct Status * statelst, * laststate;
Xstruct delrevpair * delrev;
Xstruct hshentry * cuthead, *cuttail, * delstrt;
Xchar branchnum[revlength], * branchsym;
Xstruct hshentry branchdummy;
Xchar * commsyml;
Xchar * headstate;
Xint lockhead,unlockcaller,chgheadstate,branchflag,commentflag;
Xint delaccessflag;
Xenum stringwork {copy, edit, empty}; /* expand and edit_expand not needed */
X
X
Xmain (argc, argv)
Xint argc;
Xchar * argv[];
X{
X char *comdusge;
X int result;
X struct access *removeaccess(), * getaccessor();
X struct Lockrev *rmnewlocklst();
X struct Lockrev *curlock, * rmvlock, *lockpt;
X struct Status * curstate;
X struct access *temp, *temptr;
X int status;
X
X status = 0;
X nerror = 0;
X catchints();
X cmdid = "rcs";
X quietflag = false;
X comdusge ="command format:\nrcs -i -alogins -Alogins -e[logins] -b[rev] -c[commentleader] -l[rev] -u[rev] -L -U -nname[:rev] -Nname[:rev] -orange -sstate[:rev] -t[textfile] file....";
X rplaccessor = nil; delstrt = nil;
X accessfile = textfile = caller = nil;
X branchflag = commentflag = chgheadstate = false;
X lockhead = false; unlockcaller=false;
X initflag= textflag = false;
X strict_selected = 0;
X
X caller=getcaller();
X laststate = statelst = nil;
X lastassoc = assoclst = nil;
X curlock = rmvlock = newlocklst = rmvlocklst = nil;
X curaccess = rmaccess = rmvaccessor = newaccessor = nil;
X delaccessflag = false;
X
X /* preprocessing command options */
X while (--argc,++argv, argc>=1 && ((*argv)[0] == '-')) {
X switch ((*argv)[1]) {
X
X case 'i': /* initail version */
X initflag = true;
X break;
X
X case 'b': /* change default branch */
X if (branchflag)warn("Redfinition of option -b");
X branchflag= true;
X branchsym = (*argv)+2;
X break;
X
X case 'c': /* change comment symbol */
X if (commentflag)warn("Redefinition of option -c");
X commentflag = true;
X commsyml = (*argv)+2;
X break;
X
X case 'a': /* add new accessor */
X if ( (*argv)[2] == '\0') {
X error("Login name missing after -a");
X }
X if ( (temp = getaccessor((*argv)+1)) ) {
X if ( newaccessor )
X curaccess->nextaccess = temp->nextaccess;
X else
X newaccessor = temp->nextaccess;
X temp->nextaccess = nil;
X curaccess = temp;
X }
X break;
X
X case 'A': /* append access list according to accessfile */
X if ( (*argv)[2] == '\0') {
X error("Missing file name after -A");
X break;
X }
X if ( accessfile) warn("Redefinition of option -A");
X *argv = *argv+2;
X if( pairfilenames(1, argv, true, false) > 0) {
X releaselst(newaccessor);
X newaccessor = curaccess = nil;
X releaselst(rmvaccessor);
X rmvaccessor = rmaccess = nil;
X accessfile = RCSfilename;
X }
X else
X accessfile = nil;
X break;
X
X case 'e': /* remove accessors */
X if ( (*argv)[2] == '\0' ) {
X delaccessflag = true;
X break;
X }
X if ( (temp = getaccessor((*argv)+1)) ) {
X if ( rmvaccessor )
X rmaccess->nextaccess = temp->nextaccess;
X else
X rmvaccessor = temp->nextaccess;
X temptr = temp->nextaccess;
X temp->nextaccess = nil;
X rmaccess = temp;
X while( temptr ) {
X newaccessor = removeaccess(temptr,newaccessor,false);
X temptr = temptr->nextaccess;
X }
X curaccess = temp = newaccessor;
X while( temp){
X curaccess = temp;
X temp = temp->nextaccess;
X }
X }
X break;
X
X case 'l': /* lock a revision if it is unlocked */
X if ( (*argv)[2] == '\0'){ /* lock head or def. branch */
X lockhead = true;
X break;
X }
X lockpt = (struct Lockrev *)talloc(sizeof(struct Lockrev));
X lockpt->revno = (*argv)+2;
X lockpt->nextrev = nil;
X if ( curlock )
X curlock->nextrev = lockpt;
X else
X newlocklst = lockpt;
X curlock = lockpt;
X break;
X
X case 'u': /* release lock of a locked revision */
X if ( (*argv)[2] == '\0'){ /* unlock head */
X unlockcaller=true;
X break;
X }
X lockpt = (struct Lockrev *)talloc(sizeof(struct Lockrev));
X lockpt->revno = (*argv)+2;
X lockpt->nextrev = nil;
X if (rmvlock)
X rmvlock->nextrev = lockpt;
X else
X rmvlocklst = lockpt;
X rmvlock = lockpt;
X
X curlock = rmnewlocklst(lockpt);
X break;
X
X case 'L': /* set strict locking */
X if (strict_selected++) { /* Already selected L or U? */
X if (!strictlock) /* Already selected -U? */
X warn("Option -L overrides -U");
X }
X strictlock = true;
X break;
X
X case 'U': /* release strict locking */
X if (strict_selected++) { /* Already selected L or U? */
X if (strictlock) /* Already selected -L? */
X warn("Option -L overrides -U");
X }
X else
X strictlock = false;
X break;
X
X case 'n': /* add new association: error, if name exists */
X if ( (*argv)[2] == '\0') {
X error("Missing symbolic name after -n");
X break;
X }
X getassoclst(false, (*argv)+1);
X break;
X
X case 'N': /* add or change association */
X if ( (*argv)[2] == '\0') {
X error("Missing symbolic name after -N");
X break;
X }
X getassoclst(true, (*argv)+1);
X break;
X
X case 'o': /* delete revisins */
X if (delrev) warn("Redefinition of option -o");
X if ( (*argv)[2] == '\0' ) {
X error("Missing revision range after -o");
X break;
X }
X getdelrev( (*argv)+1 );
X break;
X
X case 's': /* change state attribute of a revision */
X if ( (*argv)[2] == '\0') {
X error("State missing after -s");
X break;
X }
X getstates( (*argv)+1);
X break;
X
X case 't': /* change descriptive text */
X textflag=true;
X if ((*argv)[2]!='\0'){
X if (textfile!=nil)warn("Redefinition of -t option");
X textfile = (*argv)+2;
X }
X break;
X
X case 'q':
X quietflag = true;
X break;
X default:
X faterror("Unknown option: %s\n%s", *argv, comdusge);
X };
X } /* end processing of options */
X
X if (argc<1) faterror("No input file\n%s", comdusge);
X if (nerror) { /* exit, if any error in command options */
X diagnose("%s aborted",cmdid);
X exit(1);
X }
X if (accessfile) /* get replacement for access list */
X getrplaccess();
X if (nerror) {
X diagnose("%s aborted",cmdid);
X exit(1);
X }
X
X /* now handle all filenames */
X do {
X rewriteflag = false;
X finptr=frewrite=NULL;
X
X if ( initflag ) {
X switch( pairfilenames(argc, argv, false, false) ) {
X case -1: break; /* not exist; ok */
X case 0: continue; /* error */
X case 1: error("file %s exists already", RCSfilename);
X VOID fclose(finptr);
X continue;
X }
X }
X else {
X switch( pairfilenames(argc, argv, true, false) ) {
X case -1: continue; /* not exist */
X case 0: continue; /* errors */
X case 1: break; /* file exists; ok*/
X }
X }
X
X
X /* now RCSfilename contains the name of the RCS file, and
X * workfilename contains the name of the working file.
X * if !initflag, finptr contains the file descriptor for the
X * RCS file. The admin node is initialized.
X */
X
X diagnose("RCS file: %s", RCSfilename);
X
X if (!trydiraccess(RCSfilename)) continue; /* give up */
X if (!initflag && !checkaccesslist(caller)) continue; /* give up */
X if (!trysema(RCSfilename,true)) continue; /* give up */
X
X gettree(); /* read in delta tree */
X
X /* update admin. node */
X if (strict_selected) StrictLocks = strictlock;
X if (commentflag) Comment = commsyml;
X
X /* update default branch */
X if (branchflag && expandsym(branchsym, branchnum)) {
X if (countnumflds(branchnum)>0) {
X branchdummy.num=branchnum;
X Dbranch = &branchdummy;
X } else
X Dbranch = nil;
X }
X
X /* update access list */
X if ( delaccessflag ) AccessList = nil;
X if ( accessfile ) {
X temp = rplaccessor;
X while( temp ) {
X temptr = temp->nextaccess;
X if ( addnewaccess(temp) )
X temp->nextaccess = nil;
X temp = temptr;
X }
X }
X temp = rmvaccessor;
X while(temp) { /* remove accessors from accesslist */
X AccessList = removeaccess(temp, AccessList,true);
X temp = temp->nextaccess;
X }
X temp = newaccessor;
X while( temp) { /* add new accessors */
X temptr = temp->nextaccess;
X if ( addnewaccess( temp ) )
X temp->nextaccess = nil;
X temp = temptr;
X }
X
X updateassoc(); /* update association list */
X
X updatelocks(); /* update locks */
X
X /* update state attribution */
X if (chgheadstate) {
X /* change state of default branch or head */
X if (Dbranch==nil) {
X if (Head==nil)
X warn("Can't change states in an empty tree");
X else Head->state = headstate;
X } else {
X rcs_setstate(Dbranch->num,headstate); /* Can't set directly */
X }
X }
X curstate = statelst;
X while( curstate ) {
X rcs_setstate(curstate->revno,curstate->status);
X curstate = curstate->nextstatus;
X }
X
X cuthead = cuttail = nil;
X if ( delrev && removerevs()) {
X /* rebuild delta tree if some deltas are deleted */
X if ( cuttail )
X VOID genrevs(cuttail->num, (char *)nil,(char *)nil,
X (char *)nil, gendeltas);
X buildtree();
X }
X
X
X /* prepare for rewriting the RCS file */
X newRCSfilename=mktempfile(RCSfilename,NEWRCSFILE);
X oldumask = umask(0222); /* turn off write bits */
X if ((frewrite=fopen(newRCSfilename, "w"))==NULL) {
X VOID fclose(finptr);
X error("Can't open file %s",newRCSfilename);
X continue;
X }
X VOID umask(oldumask);
X putadmin(frewrite);
X if ( Head )
X puttree(Head, frewrite);
X putdesc(initflag,textflag,textfile,quietflag);
X rewriteflag = false;
X
X if ( Head) {
X if (!delrev) {
X /* no revision deleted */
X fastcopy(finptr,frewrite);
X } else {
X if ( cuttail )
X buildeltatext(gendeltas);
X else
X scanlogtext((struct hshentry *)nil,empty);
X /* copy rest of delta text nodes that are not deleted */
X }
X }
X ffclose(frewrite); frewrite = NULL;
X if ( ! nerror ) { /* move temporary file to RCS file if no error */
X ignoreints(); /* ignore interrupts */
X if(rename(newRCSfilename,RCSfilename)<0) {
X error("Can't create RCS file %s; saved in %s",
X RCSfilename, newRCSfilename);
X newRCSfilename[0] = '\0'; /* avoid deletion by cleanup */
X restoreints();
X VOID cleanup();
X break;
X }
X newRCSfilename[0]='\0'; /* avoid re-unlinking by cleanup()*/
X /* update mode */
X result=0;
X if (!initflag) /* preserve mode bits */
X result=chmod(RCSfilename,RCSstat.st_mode & ~0222);
X elsif (haveworkstat==0) /* initialization, and work file exists */
X result=chmod(RCSfilename,workstat.st_mode & ~0222);
X if (result<0) warn("Can't set mode of %s",RCSfilename);
X
X restoreints(); /* catch them all again */
X diagnose("done");
X } else {
X diagnose("%s aborted; %s unchanged.",cmdid,RCSfilename);
X status = 1;
X nerror = 0;
X }
X } while (cleanup(),
X ++argv, --argc >=1);
X
X exit(status);
X} /* end of main (rcs) */
X
X
X
Xgetassoclst(flag, sp)
Xint flag;
Xchar * sp;
X/* Function: associate a symbolic name to a revision or branch, */
X/* and store in assoclst */
X
X{
X struct Symrev * pt;
X char * temp, *temp2;
X int c;
X
X while( (c=(*++sp)) == ' ' || c == '\t' || c =='\n') ;
X temp = sp;
X temp2=checkid(sp, ':'); /* check for invalid symbolic name */
X sp = temp2; c = *sp; *sp = '\0';
X while( c == ' ' || c == '\t' || c == '\n') c = *++sp;
X
X if ( c != ':' && c != '\0') {
X error("Invalid string %s after option -n or -N",sp);
X return;
X }
X
X pt = (struct Symrev *)talloc(sizeof(struct Symrev));
X pt->ssymbol = temp;
X pt->override = flag;
X if (c == '\0') /* delete symbol */
X pt->revno = nil;
X else {
X while( (c = *++sp) == ' ' || c == '\n' || c == '\t') ;
X if ( c == '\0' )
X pt->revno = nil;
X else
X pt->revno = sp;
X }
X pt->nextsym = nil;
X if (lastassoc)
X lastassoc->nextsym = pt;
X else
X assoclst = pt;
X lastassoc = pt;
X return;
X}
X
X
X
Xstruct access * getaccessor( sp)
Xchar *sp;
X/* Function: get the accessor list of options -e and -a, */
X/* and store in curpt */
X
X
X{
X struct access * curpt, * pt, *pre;
X char *temp;
X register c;
X
X while( ( c = *++sp) == ' ' || c == '\n' || c == '\t' || c == ',') ;
X if ( c == '\0') {
X error("Missing login name after option -a or -e");
X return nil;
X }
X
X curpt = pt = nil;
X while( c != '\0') {
X temp=checkid(sp,',');
X pt = (struct access *)talloc(sizeof(struct access));
X pt->login = sp;
X if ( curpt )
X pre->nextaccess = pt;
X else
X curpt = pt;
X pt->nextaccess = curpt;
X pre = pt;
X sp = temp; c = *sp; *sp = '\0';
X while( c == ' ' || c == '\n' || c == '\t'|| c == ',')c =(*++sp);
X }
X return pt;
X}
X
X
X
Xgetstates(sp)
Xchar *sp;
X/* Function: get one state attribute and the corresponding */
X/* revision and store in statelst */
X
X{
X char *temp, *temp2;
X struct Status *pt;
X register c;
X
X while( (c=(*++sp)) ==' ' || c == '\t' || c == '\n') ;
X temp = sp;
X temp2=checkid(sp,':'); /* check for invalid state attribute */
X sp = temp2; c = *sp; *sp = '\0';
X while( c == ' ' || c == '\t' || c == '\n' ) c = *++sp;
X
X if ( c == '\0' ) { /* change state of def. branch or Head */
X chgheadstate = true;
X headstate = temp;
X return;
X }
X else if ( c != ':' ) {
X error("Missing ':' after state in option -s");
X return;
X }
X
X while( (c = *++sp) == ' ' || c == '\t' || c == '\n') ;
X pt = (struct Status *)talloc(sizeof(struct Status));
X pt->status = temp;
X pt->revno = sp;
X pt->nextstatus = nil;
X if (laststate)
X laststate->nextstatus = pt;
X else
X statelst = pt;
X laststate = pt;
X}
X
X
X
Xgetrplaccess()
X/* Function : get the accesslist of the 'accessfile' */
X/* and place in rplaccessor */
X{
X register char *id, *nextp;
X struct access *newaccess, *oldaccess;
X
X if ( (finptr=fopen(accessfile, "r")) == NULL) {
X faterror("Can't open file %s", accessfile);
X }
X Lexinit();
X nextp = &accessorlst[0];
X
X if ( ! getkey(Khead)) faterror("Missing head in %s", accessfile);
X VOID getnum();
X if ( ! getlex(SEMI) ) serror("Missing ';' after head in %s",accessfile);
X
X if (getkey(Kbranch)) { /* optional */
X Dbranch=getnum();
X if (!getlex(SEMI)) serror("Missing ';' after branch list");
X }
X
X
X#ifdef COMPAT2
X /* read suffix. Only in release 2 format */
X if (getkey(Ksuffix)) {
X if (nexttok==STRING) {
X readstring(); nextlex(); /*through away the suffix*/
X } elsif(nexttok==ID) {
X nextlex();
X }
X if ( ! getlex(SEMI) ) serror("Missing ';' after suffix in %s",accessfile);
X }
X#endif
X
X if (! getkey(Kaccess))fatserror("Missing access list in %s",accessfile);
X oldaccess = nil;
X while( id =getid() ) {
X newaccess = (struct access *)talloc(sizeof(struct access));
X newaccess->login = nextp;
X newaccess->nextaccess = nil;
X while( ( *nextp++ = *id++) != '\0') ;
X if ( oldaccess )
X oldaccess->nextaccess = newaccess;
X else
X rplaccessor = newaccess;
X oldaccess = newaccess;
X }
X if ( ! getlex(SEMI))serror("Missing ';' after access list in %s",accessfile);
X return;
X}
X
X
X
Xgetdelrev(sp)
Xchar *sp;
X/* Function: get revision range or branch to be deleted, */
X/* and place in delrev */
X{
X int c;
X struct delrevpair *pt;
X
X if (delrev) free((char *)delrev);
X
X pt = (struct delrevpair *)talloc(sizeof(struct delrevpair));
X while((c = (*++sp)) == ' ' || c == '\n' || c == '\t') ;
X
X if ( c == '<' || c == '-' ) { /* -o -rev or <rev */
X while( (c = (*++sp)) == ' ' || c == '\n' || c == '\t') ;
X pt->strt = sp; pt->code = 1;
X while( c != ' ' && c != '\n' && c != '\t' && c != '\0') c =(*++sp);
X *sp = '\0';
X pt->end = nil; delrev = pt;
X return;
X }
X else {
X pt->strt = sp;
X while( c != ' ' && c != '\n' && c != '\t' && c != '\0'
X && c != '-' && c != '<' ) c = *++sp;
X *sp = '\0';
X while( c == ' ' || c == '\n' || c == '\t' ) c = *++sp;
X if ( c == '\0' ) { /* -o rev or branch */
X pt->end = nil; pt->code = 0;
X delrev = pt;
X return;
X }
X if ( c != '-' && c != '<') {
X faterror("Invalid range %s %s after -o", pt->strt, sp);
X free((char *)pt);
X return;
X }
X while( (c = *++sp) == ' ' || c == '\n' || c == '\t') ;
X if ( c == '\0') { /* -o rev- or rev< */
X pt->end = nil; pt->code = 2;
X delrev = pt;
X return;
X }
X }
X /* -o rev1-rev2 or rev1<rev2 */
X pt->end = sp; pt->code = 3; delrev = pt;
X while( c!= ' ' && c != '\n' && c != '\t' && c != '\0') c = *++sp;
X *sp = '\0';
X}
X
X
X
X
Xscanlogtext(delta,func)
Xstruct hshentry * delta; enum stringwork func;
X/* Function: Scans delta text nodes up to and including the one given
X * by delta, or up to last one present, if delta==nil.
X * For the one given by delta (if delta!=nil), the log message is saved into
X * curlogmsg and the text is processed according to parameter func.
X * Assumes the initial lexeme must be read in first.
X * Does not advance nexttok after it is finished, except if delta==nil.
X */
X{ struct hshentry * nextdelta;
X
X do {
X rewriteflag = false;
X nextlex();
X if (!(nextdelta=getnum())) {
X if(delta)
X faterror("Can't find delta for revision %s", delta->num);
X else return; /* no more delta text nodes */
X }
X if ( nextdelta->selector != DELETE) {
X rewriteflag = true;
X VOID fprintf(frewrite,DELNUMFORM,nextdelta->num,Klog);
X }
X if (!getkey(Klog) || nexttok!=STRING)
X serror("Missing log entry");
X elsif (delta==nextdelta) {
X VOID savestring(curlogmsg,logsize);
X delta->log=curlogmsg;
X } else {readstring();
X if (delta!=nil) delta->log="";
X }
X nextlex();
X if (!getkey(Ktext) || nexttok!=STRING)
X fatserror("Missing delta text");
X
X if(delta==nextdelta)
X /* got the one we're looking for */
X switch (func) {
X case copy: copystring();
X break;
X case edit: editstring((struct hshentry *)nil);
X break;
X default: faterror("Wrong scanlogtext");
X }
X else readstring(); /* skip over it */
X
X } while (delta!=nextdelta);
X}
X
X
X
Xreleaselst(sourcelst)
Xstruct access * sourcelst;
X/* Function: release the storages whose address are in sourcelst */
X
X{
X struct access * pt;
X
X pt = sourcelst;
X while(pt) {
X struct access *pn = pt->nextaccess;
X free((char *)pt);
X pt = pn;
X }
X}
X
X
X
Xstruct Lockrev * rmnewlocklst(which)
Xstruct Lockrev * which;
X/* Function: remove lock to revision which->revno from newlocklst */
X
X{
X struct Lockrev * pt, *pre;
X
X while( newlocklst && (! strcmp(newlocklst->revno, which->revno))){
X struct Lockrev *pn = newlocklst->nextrev;
X free((char *)newlocklst);
X newlocklst = pn;
X }
X
X pt = pre = newlocklst;
X while( pt ) {
X if ( ! strcmp(pt->revno, which->revno) ) {
X pre->nextrev = pt->nextrev;
X free((char *)pt);
X pt = pre->nextrev;
X }
X else {
X pre = pt;
X pt = pt->nextrev;
X }
X }
X return pre;
X}
X
X
X
Xstruct access * removeaccess( who, sourcelst,flag)
Xstruct access * who, * sourcelst;
Xint flag;
X/* Function: remove the accessor-- who from sourcelst */
X
X{
X struct access *pt, *pre;
X
X pt = sourcelst;
X while( pt && (! strcmp(who->login, pt->login) )) {
X pre = pt->nextaccess;
X free((char *)pt);
X pt = pre;
X flag = false;
X }
X pre = sourcelst = pt;
X while( pt ) {
X if ( ! strcmp(who->login, pt->login) ) {
X pre->nextaccess = pt->nextaccess;
X free((char *)pt);
X pt = pre->nextaccess;
X flag = false;
X }
X else {
X pre = pt;
X pt = pt->nextaccess;
X }
X }
X if ( flag ) warn("Can't remove a nonexisting accessor %s",who->login);
X return sourcelst;
X}
X
X
X
Xint addnewaccess( who )
Xstruct access * who;
X/* Function: add new accessor-- who into AccessList */
X
X{
X struct access *pt, *pre;
X
X pre = pt = AccessList;
X
X while( pt ) {
X if ( strcmp( who->login, pt->login) ) {
X pre = pt;
X pt = pt->nextaccess;
X }
X else
X return 0;
X }
X if ( pre == pt )
X AccessList = who;
X else
X pre->nextaccess = who;
X return 1;
X}
X
X
Xsendmail(Delta, who)
Xchar * Delta, *who;
X/* Function: mail to who, informing him that his lock on delta was
X * broken by caller. Ask first whether to go ahead. Return false on
X * error or if user decides not to break the lock.
X */
X{
X char * messagefile;
X int old1, old2, c, response;
X FILE * mailmess;
X
X
X VOID fprintf(stderr, "Revision %s is already locked by %s.\n", Delta, who);
X VOID fprintf(stderr, "Do you want to break the lock? [ny](n): ");
X response=c=getchar();
X while (!(c==EOF || c=='\n')) c=getchar();/*skip to end of line*/
X if (response=='\n'||response=='n'||response=='N') return false;
X
X /* go ahead with breaking */
X messagefile=mktempfile("/tmp/", "RCSmailXXXXXX");
X if ( (mailmess = fopen(messagefile, "w")) == NULL) {
X faterror("Can't open file %s", messagefile);
X }
X
X VOID fprintf(mailmess, "Subject: Broken lock on %s\n\n",bindex(RCSfilename,'/'));
X VOID fprintf(mailmess, "Your lock on revision %s of file %s\n",Delta, getfullRCSname());
X VOID fprintf(mailmess,"has been broken by %s for the following reason:\n",caller);
X VOID fputs("State the reason for breaking the lock:\n", stderr);
X VOID fputs("(terminate with ^D or single '.')\n>> ", stderr);
X
X old1 = '\n'; old2 = ' ';
X for (; ;) {
X c = getchar();
X if ( c == EOF ) {
X VOID putc('\n',stderr);
X VOID fprintf(mailmess, "%c\n", old1);
X break;
X }
X else if ( c == '\n' && old1 == '.' && old2 == '\n')
X break;
X else {
X VOID fputc( old1, mailmess);
X old2 = old1; old1 = c;
X if (c== '\n') VOID fputs(">> ", stderr);
X }
X }
X ffclose(mailmess);
X
X /* ignore the exit status, even if delivermail unsuccessful */
X VOID run(messagefile,(char*)nil,
X#ifdef SENDMAIL
X "/usr/lib/sendmail",
X#else
X# ifdef DELIVERMAIL
X "/etc/delivermail","-w",
X# else
X "/bin/mail",
X# endif
X#endif
X who,(char*)nil);
X VOID unlink(messagefile);
X return(true);
X}
X
X
X
Xstatic breaklock(who,delta)
Xchar * who; struct hshentry * delta;
X/* function: Finds the lock held by who on delta,
X * and removes it.
X * Sends mail if a lock different from the caller's is broken.
X * Prints an error message if there is no such lock or error.
X */
X{
X register struct lock * next, * trail;
X char * num;
X struct lock dummy;
X int whor, numr;
X
X num=delta->num;
X dummy.nextlock=next=Locks;
X trail = &dummy;
X while (next!=nil) {
X if (num != nil)
X numr = strcmp(num, next->delta->num);
X
X whor=strcmp(who,next->login);
X if (whor==0 && numr==0) break; /* exact match */
X if (numr==0 && whor !=0) {
X if (!sendmail( num, next->login)){
X diagnose("%s still locked by %s",num,next->login);
X return;
X } else break; /* continue after loop */
X }
X trail=next;
X next=next->nextlock;
X }
X if (next!=nil) {
X /*found one */
X diagnose("%s unlocked",next->delta->num);
X trail->nextlock=next->nextlock;
X next->delta->lockedby=nil;
X Locks=dummy.nextlock;
X } else {
X error("no lock set on revision %s", num);
X }
X}
X
X
X
Xstruct hshentry *searchcutpt(object, length, store)
Xchar * object;
Xint length;
Xstruct hshentry * * store;
X/* Function: Search store and return entry with number being object. */
X/* cuttail = nil, if the entry is Head; otherwise, cuttail */
X/* is the entry point to the one with number being object */
X
X{
X while( compartial( (*store++)->num, object, length) ) ;
X store--;
X
X if ( *store == Head)
X cuthead = nil;
X else
X cuthead = *(store -1);
X return *store;
X}
X
X
X
Xint branchpoint(strt, tail)
Xstruct hshentry *strt, *tail;
X/* Function: check whether the deltas between strt and tail */
X/* are locked or branch point, return 1 if any is */
X/* locked or branch point; otherwise, return 0 and */
X/* mark DELETE on selector */
X
X{
X struct hshentry *pt;
X struct lock *lockpt;
X int flag;
X
X
X pt = strt;
X flag = false;
X while( pt != tail) {
X if ( pt->branches ){ /* a branch point */
X flag = true;
X error("Can't remove branch point %s", pt->num);
X }
X lockpt = Locks;
X while(lockpt && lockpt->delta != pt)
X lockpt = lockpt->nextlock;
X if ( lockpt ) {
X flag = true;
X error("Can't remove locked revision %s",pt->num);
X }
X pt = pt->next;
X }
X
X if ( ! flag ) {
X pt = strt;
X while( pt != tail ) {
X pt->selector = DELETE;
X diagnose("deleting revision %s ",pt->num);
X pt = pt->next;
X }
X }
X return flag;
X}
X
X
X
Xremoverevs()
X/* Function: get the revision range to be removed, and place the */
X/* first revision removed in delstrt, the revision before */
X/* delstrt in cuthead( nil, if delstrt is head), and the */
X/* revision after the last removed revision in cuttail(nil */
X/* if the last is a leaf */
X
X{
X struct hshentry *target, *target2, * temp, *searchcutpt();
X int length, flag;
X
X flag = false;
X if ( ! expandsym(delrev->strt, &numrev[0]) ) return 0;
X target = genrevs(&numrev[0], (char *)nil, (char *)nil, (char *)nil, gendeltas);
X if ( ! target ) return 0;
X if ( cmpnum(target->num, &numrev[0]) ) flag = true;
X length = countnumflds( &numrev[0] );
X
X if ( delrev->code == 0 ) { /* -o rev or -o branch */
X if ( length % 2)
X temp=searchcutpt(target->num,length+1,gendeltas);
X else if (flag) {
X error("Revision %s does not exist", &numrev[0]);
X return 0;
X }
X else
X temp = searchcutpt(&numrev[0],length,gendeltas);
X cuttail = target->next;
X if ( branchpoint(temp, cuttail) ) {
X cuttail = nil;
X return 0;
X }
X delstrt = temp; /* first revision to be removed */
X return 1;
X }
X
X if ( length % 2 ) { /* invalid branch after -o */
X error("Invalid branch range %s after -o", &numrev[0]);
X return 0;
X }
X
X if ( delrev->code == 1 ) { /* -o -rev */
X if ( length > 2 ) {
X temp = searchcutpt( target->num, length-1, gendeltas);
X cuttail = target->next;
X }
X else {
X temp = searchcutpt(target->num, length, gendeltas);
X cuttail = target;
X while( cuttail && ! cmpnumfld(target->num,cuttail->num,1) )
X cuttail = cuttail->next;
X }
X if ( branchpoint(temp, cuttail) ){
X cuttail = nil;
X return 0;
X }
X delstrt = temp;
X return 1;
X }
X
X if ( delrev->code == 2 ) { /* -o rev- */
X if ( length == 2 ) {
X temp = searchcutpt(target->num, 1,gendeltas);
X if ( flag)
X cuttail = target;
X else
X cuttail = target->next;
X }
X else {
X if ( flag){
X cuthead = target;
X if ( !(temp = target->next) ) return 0;
X }
X else
X temp = searchcutpt(target->num, length, gendeltas);
X getbranchno(temp->num, &numrev[0]); /* get branch number */
X target = genrevs(&numrev[0], (char *)nil, (char *)nil, (char *)nil, gendeltas);
X }
X if ( branchpoint( temp, cuttail ) ) {
X cuttail = nil;
X return 0;
X }
X delstrt = temp;
X return 1;
X }
X
X /* -o rev1-rev2 */
X if ( ! expandsym(delrev->end, &numrev[0]) ) return 0;
X if ( length != countnumflds( &numrev[0] ) ) {
X error("Invalid revision range %s-%s", target->num, &numrev[0]);
X return 0;
X }
X if ( length > 2 && compartial( &numrev[0], target->num, length-1) ) {
X error("Invalid revision range %s-%s", target->num, &numrev[0]);
X return 0;
X }
X
X target2 = genrevs( &numrev[0], (char *)nil, (char *)nil, (char *)nil,gendeltas);
X if ( ! target2 ) return 0;
X
X if ( length > 2) { /* delete revisions on branches */
X if ( cmpnum(target->num, target2->num) > 0) {
X if ( cmpnum(target2->num, &numrev[0]) )
X flag = true;
X else
X flag = false;
X temp = target;
X target = target2;
X target2 = temp;
X }
X if ( flag ) {
X if ( ! cmpnum(target->num, target2->num) ) {
X error("Revisions %s-%s don't exist", delrev->strt,delrev->end);
X return 0;
X }
X cuthead = target;
X temp = target->next;
X }
X else
X temp = searchcutpt(target->num, length, gendeltas);
X cuttail = target2->next;
X }
X else { /* delete revisions on trunk */
X if ( cmpnum( target->num, target2->num) < 0 ) {
X temp = target;
X target = target2;
X target2 = temp;
X }
X else
X if ( cmpnum(target2->num, &numrev[0]) )
X flag = true;
X else
X flag = false;
X if ( flag ) {
X if ( ! cmpnum(target->num, target2->num) ) {
X error("Revisions %s-%s don't exist", delrev->strt, delrev->end);
X return 0;
X }
X cuttail = target2;
X }
X else
X cuttail = target2->next;
X temp = searchcutpt(target->num, length, gendeltas);
X }
X if ( branchpoint(temp, cuttail) ) {
X cuttail = nil;
X return 0;
X }
X delstrt = temp;
X return 1;
X}
X
X
X
Xupdateassoc()
X/* Function: add or delete(if revno is nil) association */
X/* which is stored in assoclst */
X
X{
X struct Symrev * curassoc;
X struct assoc * pre, * pt;
X struct hshentry * target;
X
X /* add new associations */
X curassoc = assoclst;
X while( curassoc ) {
X if ( curassoc->revno == nil ) { /* delete symbol */
X pre = pt = Symbols;
X while( pt && strcmp(pt->symbol,curassoc->ssymbol) ) {
X pre = pt;
X pt = pt->nextassoc;
X }
X if ( pt )
X if ( pre == pt )
X Symbols = pt->nextassoc;
X else
X pre->nextassoc = pt->nextassoc;
X else
X warn("Can't delete nonexisting symbol %s",curassoc->ssymbol);
X }
X else if ( expandsym( curassoc->revno, &numrev[0] ) ) {
X /* add symbol */
X target = (struct hshentry *) talloc(sizeof(struct hshentry));
X target->num = &numrev[0];
X VOID addsymbol(target, curassoc->ssymbol, curassoc->override);
X }
X curassoc = curassoc->nextsym;
X }
X
X}
X
X
X
Xupdatelocks()
X/* Function: remove lock for caller or first lock if unlockcaller==true;
X * remove locks which are stored in rmvlocklst,
X * add new locks which are stored in newlocklst,
X * add lock for Dbranch or Head if lockhead==true.
X */
X{
X struct hshentry *target;
X struct Lockrev *lockpt;
X
X if(unlockcaller == true) { /* find lock for caller */
X if ( Head ) {
X if (Locks) {
X target=findlock(caller,true);
X if (target==nil) {
X breaklock(caller, Locks->delta); /* remove most recent lock */
X } else {
X diagnose("%s unlocked",target->num);
X }
X } else {
X warn("There are no locks set.");
X }
X } else {
X warn("Can't unlock an empty tree");
X }
X }
X
X /* remove locks which are stored in rmvlocklst */
X lockpt = rmvlocklst;
X while( lockpt ) {
X if (expandsym(lockpt->revno, numrev)) {
X target = genrevs(numrev, (char *)nil, (char *)nil, (char *)nil, gendeltas);
X if ( target )
X if ( !(countnumflds(numrev)%2) && cmpnum(target->num,numrev))
X error("Can't unlock nonexisting revision %s",lockpt->revno);
X else
X breaklock(caller, target);
X /* breaklock does its own diagnose */
X }
X lockpt = lockpt->nextrev;
X }
X
X /* add new locks which stored in newlocklst */
X lockpt = newlocklst;
X while( lockpt ) {
X setlock(lockpt->revno,caller);
X lockpt = lockpt->nextrev;
X }
X
X if ( lockhead == true) { /* lock default branch or head */
X if (Dbranch) {
X setlock(Dbranch->num,caller);
X } elsif ( Head) {
X if (addlock(Head, caller))
X diagnose("%s locked",Head->num);
X } else {
X warn("Can't lock an empty tree");
X }
X }
X
X}
X
X
X
Xsetlock(rev,who)
Xchar * rev, * who;
X/* Function: Given a revision or branch number, finds the correponding
X * delta and locks it for who.
X */
X{
X struct lock *lpt;
X struct hshentry *target;
X
X if (expandsym(rev, &numrev[0]) ){
X target = genrevs(&numrev[0],(char *) nil,(char *) nil,
X (char *)nil, gendeltas);
X if ( target )
X if ( !(countnumflds(&numrev[0])%2) && cmpnum(target->num,&numrev[0]))
X error("Can't lock nonexisting revision %s",numrev);
X else
X if(lpt=addlock(target, who))
X diagnose("%s locked",lpt->delta->num);
X }
X}
X
X
X
Xrcs_setstate(rev,status)
Xchar * rev, * status;
X/* Function: Given a revision or branch number, finds the corresponding delta
X * and sets its state to status.
X */
X{
X struct hshentry *target;
X
X if ( expandsym(rev, &numrev[0]) ) {
X target = genrevs(&numrev[0],(char *) nil, (char *)nil,
X (char *) nil, gendeltas);
X if ( target )
X if ( !(countnumflds(&numrev[0])%2) && cmpnum(target->num, &numrev[0]) )
X error("Can't set state of nonexisting revision %s to %s",
X numrev,status);
X else
X target->state = status;
X }
X}
X
X
X
X
X
Xbuildeltatext(deltas)
Xstruct hshentry ** deltas;
X/* Function: put the delta text on frewrite and make necessary */
X/* change to delta text */
X{
X int i, c, exit_stats;
X
X cuttail->selector = DELETE;
X initeditfiles("/tmp/");
X scanlogtext(deltas[0], copy);
X i = 1;
X if ( cuthead ) {
X cutfilename=mktempfile("/tmp/", "RCScutXXXXXX");
X if ( (fcut = fopen(cutfilename, "w")) == NULL) {
X faterror("Can't open temporary file %s", cutfilename);
X }
X
X while( deltas[i-1] != cuthead ) {
X scanlogtext(deltas[i++], edit);
X }
X
X finishedit((struct hshentry *)nil); rewind(fcopy);
X while( (c = getc(fcopy)) != EOF) VOID putc(c, fcut);
X swapeditfiles(false);
X ffclose(fcut);
X }
X
X while( deltas[i-1] != cuttail)
X scanlogtext(deltas[i++], edit);
X finishedit((struct hshentry *)nil); ffclose(fcopy);
X
X if ( cuthead ) {
X diffilename=mktempfile("/tmp/", "RCSdifXXXXXX");
X exit_stats = run((char*)nil,diffilename,
X DIFF,"-n",cutfilename,resultfile,(char*)nil);
X if (exit_stats != 0 && exit_stats != (1 << BYTESIZ))
X faterror ("diff failed");
X if(!putdtext(cuttail->num,curlogmsg,diffilename,frewrite)) return;
X }
X else
X if (!putdtext(cuttail->num,curlogmsg,resultfile,frewrite)) return;
X
X scanlogtext((struct hshentry *)nil,empty); /* read the rest of the deltas */
X}
X
X
X
Xbuildtree()
X/* Function: actually removes revisions whose selector field */
X/* is DELETE, and rebuilds the linkage of deltas. */
X/* asks for reconfirmation if deleting last revision*/
X{
X int c, response;
X
X struct hshentry * Delta;
X struct branchhead *pt, *pre;
X
X if ( cuthead )
X if ( cuthead->next == delstrt )
X cuthead->next = cuttail;
X else {
X pre = pt = cuthead->branches;
X while( pt && pt->hsh != delstrt ) {
X pre = pt;
X pt = pt->nextbranch;
X }
X if ( cuttail )
X pt->hsh = cuttail;
X else if ( pt == pre )
X cuthead->branches = pt->nextbranch;
X else
X pre->nextbranch = pt->nextbranch;
X }
X else {
X if ( cuttail == nil && !quietflag) {
X VOID fprintf(stderr,"Do you really want to delete all revisions ?[ny](n): ");
X c = response = getchar();
X while( c != EOF && c != '\n') c = getchar();
X if ( response != 'y' && response != 'Y') {
X diagnose("No revision deleted");
X Delta = delstrt;
X while( Delta) {
X Delta->selector = 'S';
X Delta = Delta->next;
X }
X return;
X }
X }
X Head = cuttail;
X }
X return;
X}
X
X@
X
X
X4.11.2.1
Xlog
X@Start of Amiga RCS port branch.
X@
Xtext
X@d6 1
Xa6 5
X<<<<<<< rcs.c
X"$Header: /u/softeng/rsbx/rcs/amiga/RCS.cbmvax/rcs.c,v 4.11.1.1 89/08/11 01:42:01 rsbx Exp Locker: rsbx $ Purdue CS";
X=======
X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 1.2 89/09/17 13:35:01 rick Exp $ Purdue CS";
X>>>>>>> 1.2
Xa36 11
X<<<<<<< rcs.c
X * Revision 4.11.1.1 89/08/11 01:42:01 rsbx
X * Start of cbmvax RCS source branch.
X=======
X * Revision 1.2 89/09/17 13:35:01 rick
X * Port to AmigaDos done by Rick Schaeffer (ricks@@iscuva.iscs.com)
X * All changes done with conditional compile (#ifdef AMIGA). This version
X * compiles correctly with Lattice C version 5.02 or later.
X>>>>>>> 1.2
X *
X<<<<<<< rcs.c
Xa37 3
X * checked in with -k by rsbx at 89.08.10.16.06.26.
X *
X * Revision 4.11 89/05/01 15:12:06 narten
Xa53 11
X=======
X * Revision 1.4 89/09/16 09:42:43 rick
X * Modified AMIGA changes to work with Lattice C
X *
X * Revision 1.3 89/09/10 09:26:56 rick
X * Moved TARGETDIR to rcs:
X *
X * Revision 1.2 88/09/03 15:08:35 rick
X * Port to AmigaDos. All done with conditional compiles
X *
X>>>>>>> 1.2
Xa133 3
X#ifdef AMIGA
X#include "stat.h"
X#else
Xa135 9
X<<<<<<< rcs.c
X=======
X#endif
X#ifdef BSD
X#include <sysexits.h>
X#else
X#define EX_OK 0
X#endif
X>>>>>>> 1.2
Xa578 5
X#ifdef AMIGA
X if (finptr != NULL)
X fclose(finptr);
X unlink(RCSfilename);
X#endif
Xa590 3
X#ifdef AMIGA
X result=chmod(RCSfilename,RCSstat.st_attr | S_IWRITE);
X#else
Xa591 1
X#endif
Xa592 3
X#ifdef AMIGA
X result=chmod(RCSfilename,workstat.st_attr | S_IWRITE);
X#else
Xa593 1
X#endif
Xd673 1
Xa673 1
X curpt = pt = pre = nil;
Xd1007 1
Xa1007 3
X#ifdef AMIGA
X return false;
X#else
Xa1057 1
X#endif AMIGA
Xa1060 1
X<<<<<<< rcs.c
Xa1062 3
X=======
Xstruct hshentry * breaklock(who,delta)
X>>>>>>> 1.2
Xa1485 3
X#ifdef AMIGA
X cutfilename=mktempfile("t:", "RCScutXXXXXX");
X#else
Xa1486 1
X#endif
Xa1505 3
X#ifdef AMIGA
X diffilename=mktempfile("t:", "RCSdifXXXXXX");
X#else
Xa1506 1
X<<<<<<< rcs.c
Xa1508 5
X=======
X#endif
X VOID sprintf(command, "%s -n %s %s >%s", DIFF,cutfilename, resultfile, diffilename);
X exit_stats = system (command);
X>>>>>>> 1.2
Xa1549 3
X#ifdef AMIGA
X fflush(stderr);
X#endif
X@
X
X
X4.11.2.2
Xlog
X@Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS
Xsources I have here (and are later than the ones Rick used).
X@
Xtext
X@d6 5
Xa10 1
X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.1 89/10/13 19:17:47 rsbx Exp Locker: rsbx $ Purdue CS";
Xd41 1
Xa41 3
X * Revision 4.11.2.1 89/10/13 19:17:47 rsbx
X * Start of Amiga RCS port branch.
X *
Xd44 6
Xd51 1
Xd72 11
Xd168 2
Xd176 1
Xa1049 1
X#ifdef AMIGA
Xd1061 2
Xa1062 40
X VOID fprintf(stderr, "Revision %s is already locked by %s.\n", Delta, who);
X VOID fprintf(stderr, "Do you want to break the lock? [ny](n): ");
X response=c=getchar();
X while (!(c==EOF || c=='\n')) c=getchar();/*skip to end of line*/
X if (response=='\n'||response=='n'||response=='N') return false;
X
X /* go ahead with breaking */
X messagefile=mktempfile("/tmp/", "RCSmailXXXXXX");
X if ( (mailmess = fopen(messagefile, "w")) == NULL) {
X faterror("Can't open file %s", messagefile);
X }
X
X VOID fprintf(mailmess, "Subject: Broken lock on %s\n\n",bindex(RCSfilename,'/'));
X VOID fprintf(mailmess, "Your lock on revision %s of file %s\n",Delta, getfullRCSname());
X VOID fprintf(mailmess,"has been broken by %s for the following reason:\n",caller);
X VOID fputs("State the reason for breaking the lock:\n", stderr);
X VOID fputs("(terminate with ^D or single '.')\n>> ", stderr);
X
X old1 = '\n'; old2 = ' ';
X for (; ;) {
X c = getchar();
X if ( c == EOF ) {
X VOID putc('\n',stderr);
X VOID fprintf(mailmess, "%c\n", old1);
X break;
X }
X else if ( c == '\n' && old1 == '.' && old2 == '\n')
X break;
X else {
X VOID fputc( old1, mailmess);
X old2 = old1; old1 = c;
X if (c== '\n') VOID fputs(">> ", stderr);
X }
X }
X ffclose(mailmess);
X
X /* ignore the exit status, even if delivermail unsuccessful */
X VOID run(messagefile,(char*)nil,
X#ifdef SENDMAIL
X "/usr/lib/sendmail",
Xa1063 24
X# ifdef DELIVERMAIL
X "/etc/delivermail","-w",
X# else
X "/bin/mail",
X# endif
X#endif
X who,(char*)nil);
X VOID unlink(messagefile);
X return(true);
X}
X
X#else
X
Xsendmail(Delta, who)
Xchar * Delta, *who;
X/* Function: mail to who, informing him that his lock on delta was
X * broken by caller. Ask first whether to go ahead. Return false on
X * error or if user decides not to break the lock.
X */
X{
X char * messagefile;
X int old1, old2, c, response;
X FILE * mailmess;
X
Xd1114 1
Xa1115 1
X#endif AMIGA
Xd1118 1
Xd1120 4
Xa1123 1
Xstatic void breaklock(who,delta)
Xd1307 1
Xa1307 1
X genrevs(&numrev[0], (char *)nil, (char *)nil, (char *)nil, gendeltas);
Xd1575 1
Xa1575 2
X#endif
X/* <<<<<<< rcs.c */
Xd1578 2
Xa1579 1
X/* =======
Xd1582 1
Xa1582 1
X>>>>>>> 1.2 */
X@
X
X
X4.11.2.3
Xlog
X@Changed file path handling to deal with Amiga file path sematics.
X@
Xtext
X@d6 1
Xa6 1
X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.2 89/10/15 15:43:36 rsbx Exp $ Purdue CS";
Xa36 4
X * Revision 4.11.2.2 89/10/15 15:43:36 rsbx
X * Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS
X * sources I have here (and are later than the ones Rick used).
X *
Xd160 1
Xa160 1
Xextern char * fnamepart();
Xd1051 1
Xa1051 1
X VOID fprintf(mailmess, "Subject: Broken lock on %s\n\n",fnamepart(RCSfilename));
Xd1116 1
Xa1116 1
X VOID fprintf(mailmess, "Subject: Broken lock on %s\n\n",fnamepart(RCSfilename));
X@
X
X
X4.11.2.4
Xlog
X@Changes to sendmail().
X@
Xtext
X@d6 1
Xa6 1
X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.3 89/10/16 19:06:13 rsbx Exp $ Purdue CS";
Xa36 3
X * Revision 4.11.2.3 89/10/16 19:06:13 rsbx
X * Changed file path handling to deal with Amiga file path sematics.
X *
Xd1031 11
Xd1043 54
Xa1103 4
X#ifdef AMIGA
X VOID fprintf(stderr, "Breaking of locks not supported by this Amiga RCS revision\n");
X return false;
X#else
Xd1158 1
Xa1159 1
X}
Xd1616 1
Xd1619 4
X@
X
X
X4.11.2.5
Xlog
X@NULL finptr after closing it.
X@
Xtext
X@d6 1
Xa6 1
X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.4 89/10/17 13:17:35 rsbx Exp $ Purdue CS";
Xa36 3
X * Revision 4.11.2.4 89/10/17 13:17:35 rsbx
X * Changes to sendmail().
X *
Xd606 1
Xa606 1
X fclose(finptr); finptr = NULL;
X@
X
X
X4.11.2.6
Xlog
X@Changes to make the delete bit to track the write bit. Made protection
Xbit manipulation less insane.
X@
Xtext
X@d6 1
Xa6 1
X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.5 89/10/30 13:38:35 rsbx Exp $ Purdue CS";
Xa36 3
X * Revision 4.11.2.5 89/10/30 13:38:35 rsbx
X * NULL finptr after closing it.
X *
Xd608 3
Xa610 8
X if (finptr != NULL) {
X fclose(finptr); finptr = NULL;
X if (chmod(RCSfilename, RCSstat.st_attr|S_IDELETE)<0)
X warn("Can't adjust mode of %s",RCSfilename);
X if (unlink(RCSfilename) != 0) { /* Remove failed */
X error("Can't unlink %s",RCSfilename);
X }
X }
Xd625 1
Xa625 1
X result=chmod(RCSfilename,RCSstat.st_attr & ~(S_IWRITE|S_IDELETE));
Xd631 1
Xa631 1
X result=chmod(RCSfilename,workstat.st_attr & ~(S_IWRITE|S_IDELETE));
Xd1533 1
Xa1533 1
X cutfilename=mktempfile("t:", "RCScutXXXXXXXX");
Xd1535 1
Xa1535 1
X cutfilename=mktempfile("/tmp/", "RCScutXXXXXXXX");
Xd1557 1
Xa1557 1
X diffilename=mktempfile("t:", "RCSdifXXXXXXXX");
Xd1559 1
Xa1559 1
X diffilename=mktempfile("/tmp/", "RCSdifXXXXXXXX");
X@
X
X
X4.11.2.7
Xlog
X@Fixed a "/tmp/" that slipped through.
X@
Xtext
X@d6 1
Xa6 1
X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.6 89/11/01 14:42:32 rsbx Exp $ Purdue CS";
Xa36 4
X * Revision 4.11.2.6 89/11/01 14:42:32 rsbx
X * Changes to make the delete bit to track the write bit. Made protection
X * bit manipulation less insane.
X *
Xa1535 3
X#ifdef AMIGA
X initeditfiles("t:");
X#else
Xa1536 1
X#endif
X@
X
X
X4.11.2.8
Xlog
X@WaitChild() on the Amiga returns the completion code from a child process
Xwithout shifting it up 8 bits like the Unix wait() does.
X@
Xtext
X@d6 1
Xa6 1
X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.7 89/11/05 23:14:17 rsbx Exp $ Purdue CS";
Xa36 3
X * Revision 4.11.2.7 89/11/05 23:14:17 rsbx
X * Fixed a "/tmp/" that slipped through.
X *
Xa1578 3
X#ifdef AMIGA
X if (exit_stats != 0 && exit_stats != 1)
X#else
Xa1579 1
X#endif
X@
X
X
X4.11.1.1
Xlog
X@Start of cbmvax RCS source branch.
X@
Xtext
X@d6 1
Xa6 1
X"$Header: /u/softeng/rsbx/rcs/rcs.uunet/src/RCS/rcs.c,v 4.11 89/05/01 15:12:06 narten Exp $ Purdue CS";
Xa36 3
X * Revision 4.11 89/05/01 15:12:06 narten
X * checked in with -k by rsbx at 89.08.10.16.06.26.
X *
X@
SHAR_EOF
echo "End of archive 7 (of 14)"
# if you want to concatenate archives, remove anything after this line
exit